package com.javaweb.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @desc: todo: 实现对 DAO层的所有方法的执行进行日志输出，日志信息
 *              包括如下：
 *              1） 方法名字
 *              2） 执行消耗时间（S）
 *
 * @author:
 * @date:
 */
@Component
@Aspect
@Slf4j
public class LogAspect {
    @Pointcut("execution(public * com.javaweb.dao..*.*(..))")
    public void daoLayerAllMethods(){} // 用一个空方法当 point Cut变量

    @Pointcut("execution(* com.javaweb.dao..*.insert*(..))")
    public void daoLayerMethodsStartWithInsert(){}

    @Before("daoLayerAllMethods()")
    public void simpleLogBeforeMethod(JoinPoint jp) {

        log.info("method: "+ jp.getSignature().getName()+" was ready for execution.") ;

    }
    // 定义一个切点，匹配所有被 @NPECatch 注解标记的方法
    @Pointcut("@within(com.javaweb.aop.NPECatch) || @annotation(com.javaweb.aop.NPECatch)")
    public void catchNullPointerExceptionPointcut() {}

    // 在抛出异常后执行
    @AfterThrowing(pointcut = "catchNullPointerExceptionPointcut()", throwing = "exception")
    public void handleNullPointerException(NullPointerException exception) {
        // 这里统一处理 NullPointerException
        System.out.println("Caught NullPointerException: " + exception.getMessage());
    }
    @After("daoLayerMethodsStartWithInsert()")
    public void afterAllInsertMethods(JoinPoint jp) {
        log.info("method: " + jp.getSignature().getName() + " was invoked no matter" +
                " whether its calling was normal nor not.") ;
    }
    @AfterReturning(pointcut = "execution(* com.javaweb.dao.CategoryDao.insert(..))", returning = "result")
    public void afterReturningAdvice(Object result) {
        if (result == null) {
            // 如果返回值为 null 且目标方法返回的是基本数据类型，打印警告
            System.out.println("Warning: Null return value detected for a method that returns a primitive type.");
        }
    }


    @Around("daoLayerAllMethods()")
    public Object measurePerformanceForAllDaoMethods(
            ProceedingJoinPoint pjp) {
        /**
         * before method execution, set a starting time.
         */
        Long start = System.currentTimeMillis() ;
        String methodName = pjp.getSignature().getName() ;
        Object ret = null ;
        try {
            ret = pjp.proceed();
        } catch (Throwable e) {
            log.error("method: " + methodName
                    + " met an error: " + e.getMessage()) ;
        }
        /**
         * after its execution, set an ending time-point.
         */
        Long end = System.currentTimeMillis() ;
        /*
          log for performance.
         */
        if (methodName.startsWith("select")) {
            log.info("method: " + methodName
                    + ", spent (s): " + (end - start) / 1000.0);
        }
        return ret ;


    }}
